import type { PlatformTypeValue } from '../../../types/interfaces'
import { BaseModule } from '../../../lib/abstract'
import { CopyButtonUpdateType } from '../../../lib/utils/base/dom'
import { ToolKit } from '../../../lib/utils/toolkit'
import {
  APP_DOM_SELECTOR_CONFIG,
  getPlatformValue,
  HOSTNAME,
  logger,
  SUPPORTED_PLATFORMS,
} from '../../../types/constants'
import { ConfigManager } from '../../config_manager'

interface Config {
  enabled?: boolean
}
interface PlatformConfig {
  selector: string
  checkSelector: string
  buttonContainer?: string
  buttonTemplate?: string | ((...args: any[]) => string)
  getCodeContent: (element: JQuery<HTMLElement>) => string
}
export const DEFAULT_COPY_BUTTON_ID: string = APP_DOM_SELECTOR_CONFIG.BUTTON.COPY.value
const DEFAULT_BUTTON_TEMPLATE = `<button id='${DEFAULT_COPY_BUTTON_ID}'>复制</button>`
type PlatformConfigs = Partial<Record<PlatformTypeValue, PlatformConfig>>

/**
 * 代码复制模块
 * 【CSDN】
 * 1) bash：https://blog.csdn.net/2402_82670467/article/details/149136848、https://blog.csdn.net/lyzybbs/article/details/149650891
 * 2) python：https://blog.csdn.net/2202_75674969/article/details/149788449
 * 3) 其他：https://blog.csdn.net/Vic10101/article/details/149783251、https://blog.csdn.net/hongkid/article/details/149746751、https://blog.csdn.net/2401_84570057/article/details/149665575、https://blog.csdn.net/A99639/article/details/149485074
 */
export class CopyProtection extends BaseModule {
  readonly id: string = 'copy_protection'
  readonly name = 'CopyProtection'
  readonly isInitialized: boolean = false
  readonly supportedPlatforms: string[] = ConfigManager.getInstance().moduleSupportedPlatforms(this.name)
  private static instance: CopyProtection
  readonly lineSelectors: Record<string, string[]> = { // 平台行选择器配置
    [SUPPORTED_PLATFORMS.CSDN]: ['.hljs-ln-line:not(.hljs-ln-n)'],
    [SUPPORTED_PLATFORMS.JUE_JIN]: ['.code-block-extension-codeLine'],
  }

  readonly platformConfigs: PlatformConfigs = { // 平台配置
    [SUPPORTED_PLATFORMS.CSDN]: {
      selector: '.hljs-button',
      checkSelector: '.hljs-button',
      getCodeContent: ($container: JQuery) => this.getCodeContent(
        HOSTNAME,
        $container,
      ),
    },
    [SUPPORTED_PLATFORMS.ZHI_HU]: {
      selector: '.highlight',
      checkSelector: '.highlight',
      buttonTemplate: (lang: string) => `
        <div class="code-block-divider">
          <span class="code-block-extension-lang">${lang}</span>
          <button id="${DEFAULT_COPY_BUTTON_ID}">
            <svg viewBox="0 0 24 24" width="16" height="16">
              <path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/>
            </svg>
            <span class="btn-text">复制</span>
          </button>
        </div>
      `,
      getCodeContent: ($container: JQuery) => $container.find('code').text().trim() || $container.text().trim(),
    },
    [SUPPORTED_PLATFORMS.JUE_JIN]: {
      selector: 'pre',
      checkSelector: '.code-block-extension-header .code-block-extension-headerRight .code-block-extension-copyCodeBtn',
      buttonTemplate: DEFAULT_BUTTON_TEMPLATE,
      getCodeContent: ($container: JQuery) => this.getCodeContent(HOSTNAME, $container),
    },
    [SUPPORTED_PLATFORMS.FIVE_ONE_CTO]: {
      selector: '.code-toolbar .hljs-cto',
      checkSelector: '.code-toolbar .hljs-cto .operation_box .copy_btn',
      buttonTemplate: DEFAULT_BUTTON_TEMPLATE,
      getCodeContent: ($container: JQuery) => $container.text().trim(),
    },
  }

  config: Config = {
    enabled: true,
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): CopyProtection {
    if (!CopyProtection.instance) {
      CopyProtection.instance = new CopyProtection()
    }
    return CopyProtection.instance
  }

  /**
   * 销毁模块
   */
  destroy(): void {
    super.destroy()
  }

  core(): void {
    this.loadConfig()

    if (!this.config.enabled)
      return

    this.setupCodeCopyButtons()
  }

  onToggleCallback(_id: string, checked: boolean): void {
    super.onToggleCallback(_id, checked)
  }

  /**
   * 执行模块核心逻辑
   */
  private setupCodeCopyButtons() {
    switch (HOSTNAME) {
      case SUPPORTED_PLATFORMS.CSDN:
        this.setupCSDNCopyButtons()
        break
      case SUPPORTED_PLATFORMS.ZHI_HU:
        this.setupZhiHuCopyButtons()
        break
      case SUPPORTED_PLATFORMS.JUE_JIN:
        this.setupJueJinCopyButtons()
        break
      case SUPPORTED_PLATFORMS.FIVE_ONE_CTO:
        this.setupFiveOneCtoCopyButtons()
        break
    }
  }

  /**
   * 获取代码块文本内容
   * @param hostname 网站域名
   * @param element JQuery DOM 元素
   */
  private getCodeContent(hostname: string, element: JQuery<HTMLElement>) {
    // 获取当前平台的行选择器
    const lineSelector = this.lineSelectors[hostname as keyof typeof this.lineSelectors] || []

    // 如果没有子元素或没有特定行选择器，直接返回文本
    if (!element.length || element.children().length === 0 || lineSelector.length === 0) {
      return element.text().trim()
    }

    // 3. 使用 find + map 优化选择器处理
    const codeLines = lineSelector
      .flatMap((selector) => {
        const matchedElements = element.find(selector)
        return matchedElements.length > 0
          ? matchedElements.toArray().map(el => el.textContent ?? '')
          : []
      })
      .filter(line => line.length > 0) // 过滤空行

    // 4. 返回结果（优先返回选择器匹配内容，否则返回完整文本）
    return codeLines.length > 0
      ? codeLines.join('\n')
      : element.text().trim()
  }

  /**
   * 解析按钮模板
   * @param template 模板字符串或函数
   * @param args 模板函数参数
   */
  private resolveButtonTemplate(
    template: string | ((...args: any[]) => string) | undefined,
    ...args: any[]
  ): string {
    if (!template)
      return DEFAULT_BUTTON_TEMPLATE
    return typeof template === 'string' ? template : template(...args)
  }

  /**
   * 获取当前平台的配置
   */
  getPlatformConfig(): PlatformConfig | undefined {
    // 获取当前平台类型
    const platformValue = getPlatformValue(HOSTNAME)
    // 类型安全访问
    return platformValue ? this.platformConfigs[platformValue] : undefined
  }

  private setupCSDNCopyButtons() {
    const config = this.getPlatformConfig()

    if (!config || !config?.selector)
      return

    const handler = () => {
      // 移除复制保护
      $(config.selector)
        .removeClass('signin') // 移除 signin 类
        .removeAttr('onclick') // 移除 onclick 属性
        .attr('data-title', '复制') // 设置新的 data-title 属性
        .on('click', async (e) => { // 新增点击事件，异步处理
          const $button = $(e.currentTarget)
          // 获取代码内容
          const $code = $button.closest('pre').find('code')
          // 检查是否为 prism 类型代码
          const isPrism = $code.hasClass('prism')
          // 获取代码内容
          const textContent = isPrism ? $code.text().trim() : config.getCodeContent($code)

          // 复制内容
          await ToolKit.dom.performCopy(textContent, $button, CopyButtonUpdateType.DataAttribute)
        })
    }

    this.setupInterval(config, handler)
  }

  private setupZhiHuCopyButtons() {
    const config = this.getPlatformConfig()

    if (!config || !config?.selector)
      return

    const handler = () => {
      // 为每个代码块添加复制按钮
      $(config.selector).each((_, element) => {
        const $highlight = $(element)
        const $pre = $highlight.find('pre')
        const $code = $pre.find('code')

        // 检查是否已添加过复制按钮
        if ($pre.find(`#${DEFAULT_COPY_BUTTON_ID}`).length > 0)
          return

        // 获取代码块语言
        const lang = $code.attr('class')?.split(' ').find(c => c.startsWith('language-'))?.replace('language-', '') || ''

        // 创建复制按钮
        const $copyBtn = $(this.resolveButtonTemplate(config.buttonTemplate, lang))

        // 添加按钮到代码块
        $pre.prepend($copyBtn)

        // 绑定复制事件
        const $effectCopyBtn = $copyBtn.find(`#${DEFAULT_COPY_BUTTON_ID}`)
        $effectCopyBtn.off('click').on('click', async (e) => {
          e.stopPropagation()
          const $button = $(e.currentTarget)

          // 获取代码内容
          const textContent = config.getCodeContent($pre)

          // 复制内容
          await ToolKit.dom.performCopy(textContent, $button.find('.btn-text'), CopyButtonUpdateType.TextContent)
        })
      })
    }

    this.setupInterval(config, handler)
  }

  private setupJueJinCopyButtons() {
    const config = this.getPlatformConfig()

    if (!config || !config?.selector)
      return

    const handler = () => {
      $(config.selector).each((_, element) => {
        const $pre = $(element)
        const $headerRight = $pre.find('.code-block-extension-header .code-block-extension-headerRight')

        // 移除原有的复制按钮
        $(`${config.checkSelector}`).remove()

        // 检查是否已处理过
        if ($headerRight.find(`#${DEFAULT_COPY_BUTTON_ID}`).length)
          return

        // 创建新按钮
        const $copyBtn = $(this.resolveButtonTemplate(config.buttonTemplate))
        $headerRight.append($copyBtn)

        // 创建按钮点击事件
        $copyBtn.off('click').on('click', async (e) => {
          ToolKit.ui.event.stopImmediatePropagation(e)

          const $button = $(e.currentTarget)

          // 获取代码内容
          const $codeBlock = $button.closest('pre').find('code')
          const textContent = config.getCodeContent($codeBlock)

          // 复制内容
          await ToolKit.dom.performCopy(textContent, $button, CopyButtonUpdateType.TextContent)
        })
      })
    }

    this.setupInterval(config, handler)
  }

  private setupFiveOneCtoCopyButtons() {
    const config = this.getPlatformConfig()

    if (!config || !config?.selector)
      return

    const handler = () => {
      $(config.selector).each((_, element) => {
        const $pre = $(element)
        const $headerRight = $pre.find('.operation_box')

        // 移除原有的复制按钮
        $(`${config.checkSelector}`).remove()

        // 检查是否已处理过
        if ($headerRight.find(`#${DEFAULT_COPY_BUTTON_ID}`).length)
          return

        // 创建新按钮
        const $copyBtn = $(this.resolveButtonTemplate(config.buttonTemplate))
        $headerRight.append($copyBtn)

        // 创建按钮点击事件
        $copyBtn.off('click').on('click', async (e) => {
          ToolKit.ui.event.stopImmediatePropagation(e)

          const $button = $(e.currentTarget)

          const $codeBlock = $button.closest('.hljs-cto').find('code')
          const textContent = config.getCodeContent($codeBlock)

          // 复制内容
          await ToolKit.dom.performCopy(textContent, $button, CopyButtonUpdateType.TextContent)
        })
      })
    }

    this.setupInterval(config, handler)
  }

  /**
   * 设置定时器检查复制按钮是否存在，存在时调用回调函数
   */
  setupInterval(config: PlatformConfig | undefined, callback: () => void): void {
    if (!config || !config?.checkSelector)
      return

    ToolKit.async.waitForCondition(
      () => $(config.checkSelector)?.length > 0,
      callback,
    )
  }

  /**
   * 应用新配置并更新模块
   */
  applyConfig(config: Partial<Config>): void {
    super.updateConfig(config)
    // 重新执行
    this.setupCodeCopyButtons()
    logger.info(`[${this.name}] Config updated and apply`, this.config)
  }
}
